package com.hs.telepass.controller.executor;

import android.content.Context;
import com.hs.teleform.R;
import com.hs.telepass.MainApp;
import com.hs.telepass.controller.task.Task;
import com.hs.telepass.utils.*;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class JsonTaskExecutor implements TaskExecutor {
    private static final int TIME_OUT = 20 * 1000;
    private static long upstream = 0;
    private static long downstream = 0;
    private static String KEY_RESPONSE_CODE = "responseCode";
    private static String KEY_RESPONSE_BODY = "responseBody";
    private Task task;
    private HttpURLConnection connection;
    private InputStream is = null;
    private OutputStream os = null;
    private InputStream fileIs = null;

    public JsonTaskExecutor(Task task) {
        this.task = task;
    }

    @Override
    public void execute(Context context) {
        // 如果任务已经取消，则直接结束
        if (task.getTaskState() == Task.TASK_STATUS_CANCELED) {
            task.onEnd();
            return;
        }


        try {
            task.onBegin();
            task.onProgress(0, 100);
            Map<String, String> responseMap;
            if(null == task.getFile())
                responseMap = doRequst(task.getJsonRequstStr());
            else
                responseMap = uploadFile(task.getFile(), task.getTaskUrl(), "", "");
            task.onProgress(100, 100);
            int responseCode = Integer.parseInt(responseMap
                    .get(KEY_RESPONSE_CODE));
            String response = responseMap.get(KEY_RESPONSE_BODY);
            if (isHttpCodeUnexpected(responseCode)) {
                task.onExecutedFail( ComonGetStringUtil.getString(R.string.error_net_with_httpcode, responseCode));
            } else if (StringUtil.isNull(response)) {
                //task.onError(1);
            } else {
                task.onExecuted(response, responseCode);
            }

        } catch (Exception e) {
            task.onExecutedFail(ComonGetStringUtil.getString(R.string.error_net_fail));
            e.printStackTrace();
        } finally {
            task.onEnd();
        }
    }

    @Override
    public void cancel() {
        // 断开连接
        IOUtil.closeSilently(os);
        IOUtil.closeSilently(is);
        IOUtil.disconnectSilently(connection);
    }


    /**
     * 根据传进来的xml body进行http请求
     *
     * @param jsonRequestStr json String
     * @return 返回保存responseCode与response内容的Map类型数据<br/>
     */
    private Map<String, String> doRequst(String jsonRequestStr)
            throws IOException {

        LogUtil.i(">>>" + task.getTaskUrl());
        LogUtil.i(">>>" + jsonRequestStr);
        try {
            URL url = new URL(task.getTaskUrl());
            connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(TIME_OUT);
            connection.setReadTimeout(TIME_OUT);
            connection.setUseCaches(false);
            connection.setDoInput(true);
            connection.setDoOutput(true);

            setRequestMethod(connection);
            if (!StringUtil.isEmpty(jsonRequestStr)) {
                // 写数据
                os = connection.getOutputStream();
                byte[] requestBytes = jsonRequestStr.getBytes();
                upstream += requestBytes.length;
                os.write(requestBytes);
                os.flush();
            }

            int responseCode = connection.getResponseCode();
            LogUtil.i("<<< HTTP Code: " + responseCode);

            Map<String, String> resultMap = new HashMap<String, String>();
            String response = "";
            // 返回状态码为204时body没有数据
            if (HttpURLConnection.HTTP_NO_CONTENT != responseCode && HttpURLConnection.HTTP_NOT_FOUND!= responseCode && HttpURLConnection.HTTP_INTERNAL_ERROR != responseCode) {
                // 读数据
                is = connection.getInputStream();
                BufferedReader br = new BufferedReader(
                        new InputStreamReader(is));
                char[] buffer = new char[1024];
                StringBuffer sb = new StringBuffer();
                int length;
                while ((length = br.read(buffer)) > 0) {
                    sb.append(buffer, 0, length);
                }
                response = sb.toString();
                downstream += response.length();
                LogUtil.i("<<<" + response);
                LogUtil.w("up: " + (upstream / 1024) + " KB");
                LogUtil.w("down: " + (downstream / 1024) + " KB");
            }

            resultMap.put(KEY_RESPONSE_CODE, responseCode + "");
            resultMap.put(KEY_RESPONSE_BODY, response);

            return resultMap;
        } finally {
            IOUtil.closeSilently(os);
            IOUtil.closeSilently(is);
        }
    }

    /**
     * 上传文件到服务器
     *
     * @param file       需要上传的文件
     * @param RequestURL 请求的rul
     * @return 返回响应的内容
     * @throws java.io.IOException
     */
    public Map<String, String> uploadFile(File file,
                                          String RequestURL, String xmlRequestStr,
                                          String xmlRequestStrName) throws IOException {
        LogUtil.i(">>>" + task.getTaskUrl());
        LogUtil.i(">>>" + xmlRequestStr);
        LogUtil.i(">>>" + file.getPath());
        Map<String, String> resultMap = new HashMap<String, String>();
        int res = 0;
        long contentLength = 0;
        long hasSendLength = 0;
        String result = null;
        String BOUNDARY = UUID.randomUUID().toString(); // 边界标识 随机生成
        String PREFIX = "--", LINE_END = "\r\n";
        String CONTENT_TYPE = "multipart/form-data"; // 内容类型
        byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINE_END).getBytes();
        StringBuffer sb = new StringBuffer();

        sb.append(PREFIX);
        sb.append(BOUNDARY);

        sb.append(LINE_END);
        //
        sb.append("Content-Disposition: form-data; name=\"" + xmlRequestStrName
                + "\"" + LINE_END);
        sb.append("Content-Type: application/xml" + LINE_END);
        sb.append(LINE_END);
        sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        sb.append(xmlRequestStr);
        sb.append(LINE_END);
        sb.append(LINE_END);

        sb.append(PREFIX);
        sb.append(BOUNDARY);
        sb.append(LINE_END);

        /**
         * 这里重点注意： name里面的值为服务器端需要key 只有这个key 才可以得到对应的文件 filename是文件的名字，包含后缀名
         */

        sb.append("Content-Disposition: form-data; name=\"" + file.getName()
                + "\"; filename=\"" + file.getName() + "\"" + LINE_END);
        sb.append("Content-Type: " + "multipart/form-data;boundary=" + UUID.randomUUID().toString() + LINE_END);
        sb.append(LINE_END);
        contentLength = sb.toString().getBytes().length;

        contentLength = contentLength + file.length()
                + LINE_END.getBytes().length + end_data.length;
        try {
            URL url = new URL(RequestURL);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setReadTimeout(TIME_OUT);
            conn.setConnectTimeout(TIME_OUT);
            conn.setDoInput(true); // 允许输入流
            conn.setDoOutput(true); // 允许输出流
            conn.setFixedLengthStreamingMode((int) contentLength);
            conn.setUseCaches(false); // 不允许使用缓存
            conn.setRequestMethod("POST"); // 请求方式

            conn.setRequestProperty("Connection", "keep-alive");
            conn.setRequestProperty("Cache-Control", "max-age=0");
            conn.setRequestProperty("Accept",
                    "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
            conn.setRequestProperty("Accept-Encoding", "gzip,deflate,sdch");
            conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary="
                    + BOUNDARY);
            conn.setRequestProperty("MIME-Version", "1.0");

            if (file != null) {
                /**
                 * 当文件不为空时执行上传
                 */
                DataOutputStream dos = new DataOutputStream(
                        conn.getOutputStream());

                dos.write(sb.toString().getBytes());
                hasSendLength = hasSendLength + sb.toString().getBytes().length;
                fileIs = new FileInputStream(file);

                byte[] bytes = new byte[20 * 1024];
                int len = 0;
                while ((len = fileIs.read(bytes)) != -1) {

                    dos.write(bytes, 0, len);
                    hasSendLength = hasSendLength + len;
//                    task.onProgress(hasSendLength, contentLength);
                }

                dos.write(LINE_END.getBytes());
                dos.write(end_data);
                dos.flush();
                dos.close();
                /**
                 * 获取响应码 200=成功 当响应成功，获取响应的流
                 */
                res = conn.getResponseCode();
                LogUtil.i("<<< HTTP Code: " + res);
                if (res == task.getResponseSuccessCode()) {
                    InputStream input = conn.getInputStream();
                    StringBuffer sb1 = new StringBuffer();
                    int ss;
                    while ((ss = input.read()) != -1) {
                        sb1.append((char) ss);
                    }
                    result = sb1.toString();
                }
                resultMap.put(KEY_RESPONSE_CODE, res + "");
                resultMap.put(KEY_RESPONSE_BODY, result);
            }
        } finally {
            IOUtil.closeSilently(is);
            IOUtil.closeSilently(fileIs);
        }

        return resultMap;
    }

    /**
     * 根据任务类型设置请求的类型
     */
    private void setRequestMethod(HttpURLConnection connection)
            throws ProtocolException {
        switch (task.getRequstType()) {
            case Task.TASK_REQUST_TYPE_POST:
                connection.setRequestMethod("POST");
                break;
            case Task.TASK_REQUST_TYPE_PUT:
                connection.setRequestMethod("PUT");
                break;
            case Task.TASK_REQUST_TYPE_GET:
                connection.setRequestMethod("GET");
                break;
            case Task.TASK_REQUST_TYPE_DELETE:
                connection.setRequestMethod("DELETE");
                break;
        }
    }

    /**
     * 判断网络状态码是否正常
     * */
    private boolean isHttpCodeUnexpected(int responseCode){
        return HttpURLConnection.HTTP_INTERNAL_ERROR == responseCode || HttpURLConnection.HTTP_NOT_FOUND == responseCode;
    }

};